#include <iostream>
#include <luaglue/luaglue.hpp>

class person
{
    public:
        person(const std::string &name)
            : m_name(name)
        {
        }

        std::string name(void)
        {
            return m_name;
        }

        virtual void self_introduce(void)
        {
            std::cout << "My name is " << m_name << "." << std::endl;
        }

    private:
        std::string         m_name;
};

class woman: public person
{
    public:
        woman(const std::string &name)
            : person(name)
        {
        }

        void self_introduce(void)
        {
            std::cout << "My name is " << name() << ". I am a woman." << std::endl;
        }

        shared_ptr<person> spawn(const std::string &name)
        {
            return shared_ptr<person>(new person(name));
        }
};

class man: public person
{
    public:
        man(const std::string &name)
            : person(name)
        {
        }

        void self_introduce(void)
        {
            std::cout << "My name is " << name() << ". I am a man." << std::endl;
        }

};

static void self_introduction(shared_ptr<person> p)
{
    p->self_introduce();
}

static shared_ptr<person> spawn(shared_ptr<woman> w, const std::string &name)
{
    return w->spawn(name);
}

extern "C" int luaopen_class(lua_State *L)
{
    luaglue::scope(L)
    [
        luaglue::class_<person, person, person>("person")
        .constructor<const std::string &>("new")
        .def("name", &person::name)
        .def("self_introduce", &person::self_introduce),

        luaglue::class_<woman, person, person>("woman")
        .constructor<const std::string &>("new")
        .def("spawn", &woman::spawn),

        luaglue::class_<man, person, person>("man")
        .constructor<const std::string &>("new"),

        luaglue::def("self_introduction", self_introduction),
        luaglue::def("spawn", spawn)
    ];

    return 0;
}

